package com.seafood.service.impl;

import com.seafood.dto.ColdChainAlertDTO;
import com.seafood.dto.ColdChainRecordDTO;
import com.seafood.dto.TemperatureLogDTO;
import com.seafood.entity.ColdChainRecord;
import com.seafood.entity.Order;
import com.seafood.entity.Product;
import com.seafood.repository.ColdChainRecordRepository;
import com.seafood.repository.OrderRepository;
import com.seafood.repository.ProductRepository;
import com.seafood.service.ColdChainAlertService;
import com.seafood.service.ColdChainRecordService;
import com.seafood.service.TemperatureLogService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 冷链运输记录服务实现
 */
@Service
@RequiredArgsConstructor
@Transactional
public class ColdChainRecordServiceImpl implements ColdChainRecordService {
    
    private final ColdChainRecordRepository coldChainRecordRepository;
    private final OrderRepository orderRepository;
    private final ProductRepository productRepository;
    private final TemperatureLogService temperatureLogService;
    private final ColdChainAlertService coldChainAlertService;
    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    @Override
    public ColdChainRecordDTO createColdChainRecord(ColdChainRecordDTO recordDTO) {
        ColdChainRecord record = new ColdChainRecord();
        copyDtoToEntity(recordDTO, record);
        
        // 生成运输单号
        if (recordDTO.getTransportNumber() == null || recordDTO.getTransportNumber().isEmpty()) {
            record.setTransportNumber(generateTransportNumber());
        }
        
        // 设置默认状态
        record.setStatus(ColdChainRecord.TransportStatus.PLANNED);
        
        ColdChainRecord saved = coldChainRecordRepository.save(record);
        return convertToDTO(saved);
    }
    
    @Override
    public ColdChainRecordDTO updateColdChainRecord(Long id, ColdChainRecordDTO recordDTO) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        copyDtoToEntity(recordDTO, record);
        ColdChainRecord updated = coldChainRecordRepository.save(record);
        return convertToDTO(updated);
    }
    
    @Override
    @Transactional(readOnly = true)
    public ColdChainRecordDTO getColdChainRecordById(Long id) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        return convertToDTO(record);
    }
    
    @Override
    @Transactional(readOnly = true)
    public ColdChainRecordDTO getColdChainRecordByTransportNumber(String transportNumber) {
        ColdChainRecord record = coldChainRecordRepository.findByTransportNumber(transportNumber)
                .orElseThrow(() -> new RuntimeException("运输单号不存在"));
        return convertToDTO(record);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<ColdChainRecordDTO> getColdChainRecordsByOrderId(Long orderId) {
        List<ColdChainRecord> records = coldChainRecordRepository.findByOrderId(orderId);
        return records.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<ColdChainRecordDTO> getColdChainRecordsByProductId(Long productId) {
        List<ColdChainRecord> records = coldChainRecordRepository.findByProductId(productId);
        return records.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<ColdChainRecordDTO> getColdChainRecords(Pageable pageable) {
        Page<ColdChainRecord> records = coldChainRecordRepository.findAll(pageable);
        return records.map(this::convertToDTO);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<ColdChainRecordDTO> getColdChainRecordsByStatus(String status, Pageable pageable) {
        ColdChainRecord.TransportStatus transportStatus = ColdChainRecord.TransportStatus.valueOf(status.toUpperCase());
        Page<ColdChainRecord> records = coldChainRecordRepository.findByStatus(transportStatus, pageable);
        return records.map(this::convertToDTO);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<ColdChainRecordDTO> getActiveTransports() {
        List<ColdChainRecord> records = coldChainRecordRepository.findActiveTransports();
        return records.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<ColdChainRecordDTO> searchByTransportCompany(String transportCompany, Pageable pageable) {
        Page<ColdChainRecord> records = coldChainRecordRepository.findByTransportCompanyContaining(transportCompany, pageable);
        return records.map(this::convertToDTO);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<ColdChainRecordDTO> getColdChainRecordsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        List<ColdChainRecord> records = coldChainRecordRepository.findByTimeRange(startTime, endTime);
        return records.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<ColdChainRecordDTO> getRecordsWithActiveAlerts() {
        List<ColdChainRecord> records = coldChainRecordRepository.findRecordsWithActiveAlerts();
        return records.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<ColdChainRecordDTO> getColdChainRecordsByQualityScoreRange(Double minScore, Double maxScore, Pageable pageable) {
        Page<ColdChainRecord> records = coldChainRecordRepository.findByQualityScoreRange(minScore, maxScore, pageable);
        return records.map(this::convertToDTO);
    }
    
    @Override
    public ColdChainRecordDTO startTransport(Long id) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        record.setStatus(ColdChainRecord.TransportStatus.IN_TRANSIT);
        record.setStartTime(LocalDateTime.now());
        
        ColdChainRecord updated = coldChainRecordRepository.save(record);
        return convertToDTO(updated);
    }
    
    @Override
    public ColdChainRecordDTO completeTransport(Long id) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        record.setStatus(ColdChainRecord.TransportStatus.DELIVERED);
        record.setEndTime(LocalDateTime.now());
        
        // 计算质量评分
        Double qualityScore = calculateQualityScore(id);
        record.setQualityScore(qualityScore != null ? BigDecimal.valueOf(qualityScore) : null);
        
        ColdChainRecord updated = coldChainRecordRepository.save(record);
        return convertToDTO(updated);
    }
    
    @Override
    public ColdChainRecordDTO cancelTransport(Long id, String reason) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        record.setStatus(ColdChainRecord.TransportStatus.CANCELLED);
        record.setNotes(record.getNotes() + "\n取消原因: " + reason);
        
        ColdChainRecord updated = coldChainRecordRepository.save(record);
        return convertToDTO(updated);
    }
    
    @Override
    public ColdChainRecordDTO updateCurrentStatus(Long id, String location, Double currentTemp, 
                                                Double currentHumidity, String gpsCoordinates) {
        ColdChainRecord record = coldChainRecordRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("冷链记录不存在"));
        
        record.setCurrentLocation(location);
        record.setCurrentTemperature(currentTemp != null ? BigDecimal.valueOf(currentTemp) : null);
        record.setCurrentHumidity(currentHumidity != null ? BigDecimal.valueOf(currentHumidity) : null);
        record.setGpsCoordinates(gpsCoordinates);
        
        ColdChainRecord updated = coldChainRecordRepository.save(record);
        return convertToDTO(updated);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Double calculateQualityScore(Long id) {
        // 获取温度日志和报警信息来计算质量评分
        Long abnormalLogs = temperatureLogService.countAbnormalLogs(id);
        Long unresolvedAlerts = coldChainAlertService.countUnresolvedAlerts(id);
        
        // 简单的评分算法：基础分100，每个异常温度记录扣2分，每个未解决报警扣5分
        double score = 100.0 - (abnormalLogs * 2) - (unresolvedAlerts * 5);
        return Math.max(0.0, Math.min(100.0, score));
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> getTransportStatistics() {
        List<Object[]> statusCounts = coldChainRecordRepository.countByStatus();
        Map<String, Object> statistics = new HashMap<>();
        
        for (Object[] row : statusCounts) {
            statistics.put(row[0].toString(), row[1]);
        }
        
        return statistics;
    }
    
    @Override
    public void deleteColdChainRecord(Long id) {
        coldChainRecordRepository.deleteById(id);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Object> generateTransportReport(Long id) {
        ColdChainRecordDTO record = getColdChainRecordById(id);
        Map<String, Object> temperatureStats = temperatureLogService.getTemperatureStatistics(id);
        Map<String, Object> humidityStats = temperatureLogService.getHumidityStatistics(id);
        List<ColdChainAlertDTO> alerts = coldChainAlertService.getColdChainAlertsByColdChainRecordId(id);
        
        Map<String, Object> report = new HashMap<>();
        report.put("record", record);
        report.put("temperatureStatistics", temperatureStats);
        report.put("humidityStatistics", humidityStats);
        report.put("alerts", alerts);
        report.put("qualityScore", record.getQualityScore());
        
        return report;
    }
    
    private void copyDtoToEntity(ColdChainRecordDTO dto, ColdChainRecord entity) {
        if (dto.getOrderId() != null) {
            Order order = orderRepository.findById(dto.getOrderId())
                    .orElseThrow(() -> new RuntimeException("订单不存在"));
            entity.setOrder(order);
        }
        
        if (dto.getProductId() != null) {
            Product product = productRepository.findById(dto.getProductId())
                    .orElseThrow(() -> new RuntimeException("产品不存在"));
            entity.setProduct(product);
        }
        
        entity.setTransportNumber(dto.getTransportNumber());
        entity.setTransportCompany(dto.getTransportCompany());
        entity.setVehicleInfo(dto.getVehicleInfo());
        entity.setDriverInfo(dto.getDriverInfo());
        entity.setOriginAddress(dto.getOriginAddress());
        entity.setDestinationAddress(dto.getDestinationAddress());
        entity.setPlannedTempMin(dto.getPlannedTempMin());
        entity.setPlannedTempMax(dto.getPlannedTempMax());
        entity.setPlannedHumidityMin(dto.getPlannedHumidityMin());
        entity.setPlannedHumidityMax(dto.getPlannedHumidityMax());
        entity.setEstimatedDurationHours(dto.getEstimatedDurationHours());
        entity.setCurrentLocation(dto.getCurrentLocation());
        entity.setCurrentTemperature(dto.getCurrentTemperature());
        entity.setCurrentHumidity(dto.getCurrentHumidity());
        entity.setGpsCoordinates(dto.getGpsCoordinates());
        entity.setQualityScore(dto.getQualityScore());
        entity.setNotes(dto.getNotes());
        
        if (dto.getStatus() != null && !dto.getStatus().isEmpty()) {
            entity.setStatus(ColdChainRecord.TransportStatus.valueOf(dto.getStatus().toUpperCase()));
        }
        
        if (dto.getStartTime() != null && !dto.getStartTime().isEmpty()) {
            entity.setStartTime(LocalDateTime.parse(dto.getStartTime(), FORMATTER));
        }
        
        if (dto.getEndTime() != null && !dto.getEndTime().isEmpty()) {
            entity.setEndTime(LocalDateTime.parse(dto.getEndTime(), FORMATTER));
        }
    }
    
    private ColdChainRecordDTO convertToDTO(ColdChainRecord entity) {
        ColdChainRecordDTO dto = new ColdChainRecordDTO();
        BeanUtils.copyProperties(entity, dto);
        
        if (entity.getOrder() != null) {
            dto.setOrderId(entity.getOrder().getId());
            dto.setOrderNumber(entity.getOrder().getOrderNumber());
        }
        
        if (entity.getProduct() != null) {
            dto.setProductId(entity.getProduct().getId());
            dto.setProductName(entity.getProduct().getName());
        }
        
        dto.setStatus(entity.getStatus().name());
        dto.setStartTime(entity.getStartTime() != null ? entity.getStartTime().format(FORMATTER) : null);
        dto.setEndTime(entity.getEndTime() != null ? entity.getEndTime().format(FORMATTER) : null);
        dto.setCreatedAt(entity.getCreatedAt() != null ? entity.getCreatedAt().format(FORMATTER) : null);
        dto.setUpdatedAt(entity.getUpdatedAt() != null ? entity.getUpdatedAt().format(FORMATTER) : null);
        
        // 设置报警数量
        Long alertCount = coldChainAlertService.countUnresolvedAlerts(entity.getId());
        dto.setAlertCount(alertCount.intValue());
        
        return dto;
    }
    
    private String generateTransportNumber() {
        return "CC" + System.currentTimeMillis() + String.format("%04d", new Random().nextInt(10000));
    }
}